/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
/*
 * Toplogy Viewer
 */


package cgl.narada.topology.viewer;

import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * This class represents a virtual node (BIG Broker node) which consists of all
 * super super clusetrs. This virtual node is a BIG invisible circle on the 
 * screen which contains all types of nodes and information. It separated node
 * management system from the main tree.
 */
public class VirtualNode extends Node {
    public List superSuperClusters;
    
    /**
     * Only constructor.
     */
    public VirtualNode() {
	// form a node for this cluster. Initialize all the Ids and Position.
	super(INVALID_VALUE, INVALID_VALUE, INVALID_VALUE, INVALID_VALUE);
	superSuperClusters = new ArrayList();
    }

    /**
     * Add a new super super cluster to the list. Depending upon the total 
     * number of super super clusters in the list, decide the new positions
     * for each of the super super cluster.
     * @param  superSuperClusterId id of a super super cluster.
     * @param  superClusterId id of a super cluster.
     * @param  clusterId id of a cluster.
     * @param  nodeId id of a node.
     * @throws TopologyException if due to some problem. super super cluster is
     *         found null during insertion of a node
     *
     */
    public void insertSuperSuperCluster(int superSuperClusterId,
					int superClusterId, int clusterId,
					int nodeId) 
	throws TopologyException {
	// Addition of the super super cluster
	SSCluster superSuperCluster = new SSCluster();
	superSuperCluster = getSuperSuperCluster(superSuperClusterId);
	if (superSuperCluster == null) {
	    SSCluster superSuperCluster1 = new SSCluster(superSuperClusterId);
	    superSuperClusters.add(superSuperCluster1);	
	    repositionSuperSuperClusters();
	}
	// Addition of the super cluster
	superSuperCluster = getSuperSuperCluster(superSuperClusterId);
	if (superSuperCluster == null) {
	    throw new TopologyException("super super cluster not found while"
					+ "insertion");
	} else {
	    superSuperCluster.insertSuperCluster(superClusterId, clusterId,
						 nodeId);
	}
    }
    
    /**
     * Deletes an existing super super cluster inside the virtual node.
     * Repositions all other nodes reculrsively. 
     * @param  superSuperClusterId id of a super super cluster.
     * @param  superClusterId id of a super cluster.
     * @param  clusterId id of a cluster.
     * @param  nodeId id of a node.
     * @param  nodesToBeDeleted a <code>List</code> which will contain node
     *         addresses of the nodes being deleted.
     * @throws TopologyException if no such super super cluster id found while 
     *         node deletion.
     */
    public void deleteSuperSuperCluster(int superSuperClusterId, 
					int superClusterId, int clusterId, 
					int nodeId, List nodesToBeDeleted) 
	throws TopologyException {
	Iterator it = superSuperClusters.iterator();
	boolean superSuperClusterFound = false;
	while ((it.hasNext()) && (!superSuperClusterFound)) {
	    SSCluster superSuperCluster = (SSCluster) it.next();
	    if (superSuperCluster.nodeId == superSuperClusterId) {
		if (superClusterId == INVALID_VALUE) {
		    superSuperCluster.deleteAllSuperClusters(nodesToBeDeleted);
		} else {
		    superSuperCluster.deleteSuperCluster(superClusterId, 
							 clusterId,
							 nodeId,
							 nodesToBeDeleted);
		}
		// if the super super cluster is empty then delete it
		if (superSuperCluster.superClusters.isEmpty()) {
		    it.remove();
		    repositionSuperSuperClusters();
		}
		superSuperClusterFound = true;
	    }
	}
	if (!superSuperClusterFound) {
	    throw new TopologyException("error in node deletion");
	}
    }

    /**
     * Deletes all the super super clusters present in the system cluster.
     * @param nodesToBeDeleted a <code>List</code> which will contain node
     *        addresses of the nodes being deleted.
     */
     public void deleteAllSuperSuperClusters(List nodesToBeDeleted) {
	Iterator it = superSuperClusters.iterator();
	while (it.hasNext()) {
	    SSCluster ssc = (SSCluster) it.next();
	    ssc.deleteAllSuperClusters(nodesToBeDeleted);
	    it.remove();
	}
    }

    /**
     * Finds out super super cluster nearest to the specified coordinates. Then
     * passes control to the super super cluster for finding a nearest 
     * super cluster.
     * @param  x X-coordinate
     * @param  y Y-coordinate
     * @return <code>Node</code> nearest to specified coordinates.
     */
    public Node getNodeAtParticularCoordinates(int x, int y) {
	SSCluster ssc = 
	    (SSCluster) PositionCalculation.getNearestNode(superSuperClusters,
							   x, y);
	if (ssc != null) {
	    return ssc.getNodeAtParticularCoordinates(x, y);
	}
	return null;
    }

    /**
     * Draws the virtual node only if its part is visible on the screen.
     * Draws all the super super clusters inside it.
     * @param  g <code>Graphics</code> object for image drawing.
     * @param  limitX1 lower limit for X-coordinate
     * @param  limitY1 lower limit for Y-coordinate
     * @param  limitX2 upper limit for X-coordinate
     * @param  limitY2 upper limit for Y-coordinate
     */
    public void drawVirtualNode(Graphics g, int limitX1, int limitY1,
				int limitX2, int limitY2) {
	// first draw all the nodes.
	Iterator itSSClusters = superSuperClusters.iterator();
	SSCluster ssc;
	if (this.canFitOnPanel(limitX1, limitY1, limitX2, limitY2)) {
	    while (itSSClusters.hasNext()) {
		ssc = (SSCluster) itSSClusters.next();
		ssc.drawSuperSuperCluster(g, limitX1, limitY1, limitX2, 
					  limitY2);
	    }
	}
    }

    /**
     * Returns a <code>String</code> containing information about counts
     * of individual components.
     */
    public String getAllCounts() {
	int num1, num2, num3, num4;
	num1 = num2 = num3 = num4 = 0;
	Iterator itSSClusters = superSuperClusters.iterator();
	while (itSSClusters.hasNext()) {
	    SSCluster ssc = (SSCluster) itSSClusters.next();
	    num2 += ssc.superClusters.size();
	    Iterator itSClusters = ssc.superClusters.iterator();
	    while (itSClusters.hasNext()) {
		SCluster sc = (SCluster) itSClusters.next();
		num3 += sc.clusters.size();
		Iterator itClusters = sc.clusters.iterator();
		while (itClusters.hasNext()) {
		    Cluster c = (Cluster) itClusters.next();
		    num4 += c.nodes.size();
		}
	    }
	}
	num1 = superSuperClusters.size();
	String s = "SSClusters = " + num1 +
	    ",  SClusters = " + num2 +
	    ",  Clusters = " + num3 +
	    ",  Nodes = " + num4;
	return s;
    }

    /**
     * Returns a node in the system with specified super super cluster, super
     * cluster, cluster and node id.
     * @param  superSuperClusterId id of a super super cluster.
     * @param  superClusterId id of a super cluster.
     * @param  clusterId id of a cluster.
     * @param  nodeId id of a node.
     * @return <code>Node</code> 
     */
    public Node getParticularNode(int superSuperClusterId, int superClusterId,
				  int clusterId, int nodeId) {
	SSCluster superSuperCluster = 
	    getSuperSuperCluster(superSuperClusterId);
	if (superSuperCluster != null) {
	    return superSuperCluster.getParticularNode(superClusterId,
						       clusterId, nodeId);
	}
	return null;
    }

    /**
     * Gets the new <code>Position</code> objects and assign then to all the 
     * super super clusters inside the system. Recurdively calls
     * repositionNodes() for each of the super super cluster.
     */
    public void repositionSuperSuperClusters() {
	List newPositions = getNewPositions();
	Iterator itPosition = newPositions.iterator();
	Iterator itSuperSuperCluster = superSuperClusters.iterator();
	while (itSuperSuperCluster.hasNext()) {
	    SSCluster ssc = (SSCluster) itSuperSuperCluster.next();
	    Position p = (Position) itPosition.next();
	    ssc.nodeLocation = p;
	    ssc.repositionSuperClusters();
	}
    }

    /**
     * Returns particular super super cluster with specified id
     * @param  superSuperClusterId id of a super super cluster.
     * @return <code>SSCluster</code>
     */
    private SSCluster getSuperSuperCluster(int superSuperClusterId) {
	Iterator it = superSuperClusters.iterator();
	while (it.hasNext()) {
	    SSCluster ssc = (SSCluster) it.next();
	    if (ssc.nodeId == superSuperClusterId) {
		return ssc;
	    }
	}
	return null;
    }
    /**
     * Returns a <code>List</code> containing <code>Position</code> objects
     * for all the super super clusters inside the system.
     * @return <code>List</code> of new Position objects.
     */
    private List getNewPositions() {
	int numberOfNodes = superSuperClusters.size();
	return PositionCalculation.getNewPositions(this.nodeLocation,
						   numberOfNodes, 1);	    
    }
};
